/*
*	Project: Aethon
*
*	File: StageHand.cpp
*
*	Author: Caleb Reinking
*
*	Date: 2/15/2009
*
*   Purpose: The stage hand is the command console that will be used during
*            gameplay. It will be used to debug and report information as well
*            as control certain settings such as visibility and collisions.
*            StageHand Class Implementation File
*
*   Citations: Drawing Overlay using drawOverlay, viewPerspective, viewOrtho help
*              found at the following site:
*              http://www.idevgames.com/forum/showthread.php?t=16597 
*
*              Printing Text to the screen using printText() help found at:
*              www.letu.edu/people/jaytevis/Computer-Graphics/Example-Programs/FontsWithMenu.cpp
*/

#include "../include/StageHand.h"
#include <iostream>
#include <string>

using namespace std;

	//singleton pattern based on http://www.inquiry.com/techtips/cpp_pro/10min/10min0200.asp
    StageHand* StageHand::pinstance = 0;
    
    StageHand* StageHand::getInstanceOf()//returns instance of StageHand
	{
		if (pinstance == 0)  // is it the first call?
		{  
		pinstance = new StageHand(); // create sole instance
		}
		return pinstance; // address of sole instance
	}//end get instance of

//-------------------------------------------------------------------------	
//------------------- Methods ---------------------------------------------
//##########################################################################
void StageHand::keyboardHandle(unsigned char key, int x, int y)
{
  // cout << "The OpenGL program Keyboard Handler Callback Function" << endl;
      
   StageHand *theStageHand = StageHand::getInstanceOf();
   string tempBuf;

   switch(key)
   {    
      case '`': //regiters stage handler's keyboard function
      case '~': theStageHand->setIsActive(!theStageHand->getIsActive());
                *(theStageHand->getHandleNumberPtr())=1;//tells director to check for active control handler
                break;
      case 13: theStageHand->commandParser( theStageHand->getCommandBuffer() );
                theStageHand->pushCommand( theStageHand->getCommandBuffer() );
                theStageHand->setCommandBuffer(""); 
                break;
      case 8: tempBuf = theStageHand->getCommandBuffer();
                tempBuf = tempBuf.substr(0,tempBuf.size()-1);
                theStageHand->setCommandBuffer(tempBuf); 
                break;
                
      default : tempBuf = theStageHand->getCommandBuffer();
                tempBuf.push_back( key );
                theStageHand->setCommandBuffer(tempBuf);               
   }//end switch
   
} // end keyboardHandler

void StageHand::specialHandle(int key, int x, int y)
{
     StageHand *theStageHand = StageHand::getInstanceOf();
     string tempBuf;
     
     switch(key)
     {
        case GLUT_KEY_UP : theStageHand->setCommandBuffer(theStageHand->getLastCommand()); break;
        default: break;
     }
}
	
//##########################################################################
char StageHand::specialHandle()
{
	cout << "StageHand::specialHandle() returning 'a'\n";
   //cout << "The OpenGL Special Key Handler Callback Function" << endl;
   return 'a';
} // end specialHandler

//##########################################################################
void StageHand::display( int windowHeight, int windowWidth )
{
   if(isActive)
   {
       glPushMatrix();
       glDisable(GL_DEPTH_TEST);
	   glDepthMask(GL_FALSE);
	   viewOrtho(windowHeight, windowWidth);
	   
       drawOverlay( windowHeight, windowWidth );
         
       glColor3f(0.0f,0.0f,1.0f);
       printConsole();
       
	   viewPerspective();
	   glEnable(GL_DEPTH_TEST);
	   glDepthMask(GL_TRUE);
	   
	   glPopMatrix();
   }  
   
   //cout << "Draws the translucent command shell overlay on the screen" 
     //   << endl;
} // end display

	
//##########################################################################
void StageHand::commandParser(string parseStr)
{
   vector<Model>* listPtr = getScenePtr()->getModListPtr();
     
   if( parseStr.compare("walk") == 0 )
   {
      (*listPtr)[1].pushMovement("tilion_walk");
      (*listPtr)[1].toggleCollisionSphereVisibility();
   }
   else if( parseStr.compare("tc") == 0 )
   {
      (*listPtr)[scenePtr->getCurrentModIndex()].toggleCollisionSphereVisibility();
      commandBuffer = commandBuffer + " :: Current Model Collision Sphere Toggled.";
   }
   else if( parseStr.compare("tc -a") == 0 )
   {
      for( int i = 0 ; i < (int)(*listPtr).size() ; i++ )
      {
         (*listPtr)[i].toggleCollisionSphereVisibility();
      }
      commandBuffer = commandBuffer + " :: All Collision Spheres Toggled.";
   }
   else if( parseStr.compare("tv") == 0 )
   {
      (*listPtr)[scenePtr->getCurrentModIndex()].setHasVisibility(!(*listPtr)[scenePtr->getCurrentModIndex()].getHasVisibility());
      commandBuffer = commandBuffer + " :: Current Model Collision Sphere Toggled.";
   }
   else if( parseStr.compare("tv -a") == 0 )
   {
      for( int i = 0 ; i < (int)(*listPtr).size() ; i++ )
      {
         (*listPtr)[i].setHasVisibility(!(*listPtr)[scenePtr->getCurrentModIndex()].getHasVisibility());
      }
      commandBuffer = commandBuffer + " :: All Model Visibility Toggled.";
   }
   else if( parseStr.compare("model?") == 0)
      commandBuffer = commandBuffer + " :: Current Model: " + scenePtr->getCurrentModel();
   else if( parseStr.compare("+") == 0)
   {
      scenePtr->toggleNextControl();
      commandBuffer = commandBuffer + " :: Current Model: " + scenePtr->getCurrentModel();
   }
   else if( parseStr.compare("-") == 0)
   {
      scenePtr->togglePreviousControl();
      commandBuffer = commandBuffer + " :: Current Model: " + scenePtr->getCurrentModel();
   }
   else if( parseStr.compare("can't touch this") == 0)
   {
      scenePtr->toggleCollisions();
   }
   
   else if( parseStr.compare("size") == 0)
   {
	  cout<< "width: "<<glutGet(GLUT_WINDOW_WIDTH);
	  cout<< "   height: "<<glutGet(GLUT_WINDOW_HEIGHT)<<endl;
   }
   
   else if( parseStr.compare("where?") == 0)
   {
		vector3f position = (*listPtr)[scenePtr->getCurrentModIndex()].getPosition();
		fprintf(stderr, "current Position = X: %2.1f, Y: %2.1f, Z: %2.1f\n",position.v[0],position.v[1],position.v[2]);
   }
   
      else if( parseStr.compare("invertLook") == 0)
   {
		Control::getInstanceOf()->toggleInversion();
   }
   
      else if( parseStr.compare("invertHorizLook") == 0)
   {
		Control::getInstanceOf()->toggleHorizInversion();
   }
   
   else if(parseStr.compare("quit") == 0 )
      exit(0);
   else commandBuffer = commandBuffer + " :: Unknown command.";
     
   //cout << "void StageHand::commandParser( string parseStr )" << endl;
   //cout << "Parses the string into several different commands and/or options"
     //   << endl << endl;
}

//#########################################################################
void StageHand::executeCommand(string cmdTokens)
{
   cout << "void StageHand::executeCommand( string[] cmdList )" << endl;
   cout << "Takes a list of commands and issues them to the Director"
        << endl << endl;
}

void StageHand::drawOverlay(int windowHeight, int windowWidth )
{
	
	glEnable (GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); 
	glColor3f(0.0f,1.0f,0.0f);
	glBegin(GL_QUADS);
	   glVertex2f(0, 0);
	   glVertex2f(0, windowHeight/4.0);
	   glVertex2f(windowWidth, windowHeight/4.0);
	   glVertex2f(windowWidth, 0);
	glEnd();
    glDisable (GL_BLEND);
	
}

void StageHand::viewOrtho(int x, int y)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho( 0, x , y , 0, -1, 1 );
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
}

void StageHand::viewPerspective(void)
{
	glMatrixMode( GL_PROJECTION );
	glPopMatrix();
	glMatrixMode( GL_MODELVIEW );
	glPopMatrix();
}

void StageHand::printConsole()
{
   const float X_BASE = 30;
   const float STEP_SIZE = 18;
   const float OFFSET = 5;
   static int i;  
   const int PREV_CMDS_SHOWN = 4;
     
   for( i = PREV_CMDS_SHOWN; i > 0 ; i-- )
   {
        if( (int)(commandList.size())-i >= 0 )
        {
           //cout << commandList.size() << " - " << i << endl;
           //cout << commandList.size()-i << endl;
           printText( GLUT_BITMAP_HELVETICA_12, X_BASE, OFFSET + (PREV_CMDS_SHOWN-i+1)*STEP_SIZE, 
                      ">    " + commandList[commandList.size()-i] );
        }// end if
        else printText( GLUT_BITMAP_HELVETICA_12, X_BASE, 
                        OFFSET + (PREV_CMDS_SHOWN-i+1)*STEP_SIZE, ">    " );      
   }// end for
      
   printText( GLUT_BITMAP_HELVETICA_12, X_BASE, OFFSET+5*STEP_SIZE, ">    " + commandBuffer);
    
}

//########################################################
void StageHand::printText(void *font, float x, float y, string textStr)
{
int i;
int length = textStr.length();

//char* text = new char[textStr.length()];

strcpy( cmdBufChar, textStr.c_str() );

glRasterPos3f(x, y, 0.0);
for (i = 0; i < length; i++)
   glutBitmapCharacter(font, cmdBufChar[i]);
} // End printText

